package com.sa.commons.dao.hiber.query;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;

import com.sa.commons.dao.hiber.query.inter.GenericQuery;
import com.sa.commons.dao.hiber.util.CreateHqlUtil;
import com.sa.commons.dao.hiber.util.Element;

import com.sa.commons.dao.hiber.GenericDaoImpl;
import com.sa.commons.dao.hiber.OrderType;
import com.sa.commons.dao.hiber.basic.HibernateSessionFactory;
import com.sa.commons.exception.DBDataErrorException;
import com.sa.commons.exception.DBErrorException;

/**
 * 查询类
 * 
 * @author 黄欣
 * 
 * @param <E>
 */
public class GenericQueryHqlImpl<PK, E> extends GenericDaoImpl<PK, E> implements
		GenericQuery<E> {

	private static final Log log = LogFactory.getLog(GenericQueryHqlImpl.class);

	public GenericQueryHqlImpl(Class<? extends E> entityClass) {
		super(entityClass);
	}

	@SuppressWarnings("unchecked")
	public GenericQueryHqlImpl(String entityClassName) {
		super(entityClassName);
	}

	public Session getSession() {
		return HibernateSessionFactory.getSession();
	}

	public long countEntity(Map<String, ?> equalsMap,
			Map<String, ? extends Object[]> inMap, Map<String, String> likeMap)
			throws DBErrorException, DBDataErrorException {
		log.debug("countEntity for class:" + getEntityClass().getName());

		StringBuffer hql = new StringBuffer("select count(*) from "
				+ getEntityClass().getName()
				+ this.createQueryHql(equalsMap, inMap, likeMap));

		try {
			Query query = getSession().createQuery(hql.toString());
			Object object = query.uniqueResult();
			if (null == object) {
				return 0;
			}
			return Long.parseLong(object.toString());
		} catch (RuntimeException re) {
			log.error("findEntity for class=" + getEntityClass().getName()
					+ " failed!", re);
			throw re;
		}
	}

	public long countEntity(Map<String, ?> equalsMap,
			Map<String, ? extends Object[]> inMap) throws DBErrorException,
			DBDataErrorException {
		return this.countEntity(equalsMap, inMap, null);
	}

	public long countEntity(Map<String, ?> equalsMap) throws DBErrorException,
			DBDataErrorException {
		return this.countEntity(equalsMap, null, null);
	}

	@SuppressWarnings("unchecked")
	public List<E> findEntity(Map<String, ?> equalsMap,
			Map<String, ? extends Object[]> inMap, Map<String, String> likeMap,
			Map<String, OrderType> orderMap, int firstResult, int maxResult)
			throws DBErrorException, DBDataErrorException {

		log.debug("findEntity for class:" + getEntityClass().getName());

		StringBuffer hql = new StringBuffer("from "
				+ getEntityClass().getName()
				+ this.createQueryHql(equalsMap, inMap, likeMap));

		/**
		 * 动态生成排序语句
		 */
		boolean hasOrder = (orderMap == null) ? false : !orderMap.isEmpty();
		if (hasOrder) {
			hql.append(" order by ");
			for (Iterator<Map.Entry<String, OrderType>> iterator = orderMap
					.entrySet().iterator(); iterator.hasNext();) {
				Map.Entry<String, OrderType> entry = iterator.next();
				hql.append(entry.getKey() + " " + entry.getValue());
				if (iterator.hasNext()) {
					hql.append(",");
				}
			}
		}

		try {
			Query query = getSession().createQuery(hql.toString());
			System.out.println("hql:"+hql);
			/**
			 * 当maxResult大于零的时候设置分页属性
			 */
			if (maxResult > 0) {
				query.setFirstResult(firstResult).setMaxResults(maxResult);
			}
			return query.list();
		} catch (RuntimeException re) {
			log.error("findEntity for class=" + getEntityClass().getName()
					+ " failed!", re);
			throw new DBDataErrorException(
					"动态生成排序语句的查询出错，package： com.sa.util.dao.query");
		}
	}

	public List<E> findEntity(Map<String, ?> equalsMap,
			Map<String, ? extends Object[]> inMap,
			Map<String, OrderType> orderMap, int firstResult, int maxResult)
			throws DBErrorException, DBDataErrorException {
		return this.findEntity(equalsMap, inMap, null, orderMap, firstResult,
				maxResult);
	}

	public List<E> findEntity(Map<String, ?> equalsMap,
			Map<String, OrderType> orderMap, int firstResult, int maxResult)
			throws DBErrorException, DBDataErrorException {
		return this.findEntity(equalsMap, null, null, orderMap, firstResult,
				maxResult);
	}

	public List<E> findEntity(Map<String, ?> equalsMap, int firstResult,
			int maxResult) throws DBErrorException, DBDataErrorException {
		return this.findEntity(equalsMap, null, null, null, firstResult,
				maxResult);
	}

	public List<E> findEntity(Map<String, ?> equalsMap,
			Map<String, ? extends Object[]> inMap, Map<String, String> likeMap,
			Map<String, OrderType> orderMap) throws DBErrorException,
			DBDataErrorException {
		return this.findEntity(equalsMap, inMap, null, orderMap, 0, -1);
	}

	private String createQueryHql(Map<String, ?> equalsMap,
			Map<String, ? extends Object[]> inMap, Map<String, String> likeMap) {
		return CreateHqlUtil.createQueryHql(equalsMap, inMap, likeMap);
	}

	public Class<? extends E> getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class<? extends E> entityClass) {
		this.entityClass = entityClass;
	}

	public long countEntityByList(List<Element> elements)
			throws DBErrorException, DBDataErrorException {
		log.debug("findEntity for class:" + getEntityClass().getName());

		StringBuffer hql = new StringBuffer("select count(*) from "
				+ getEntityClass().getName() + this.createQueryHql(elements));
		System.out.println("hql:" + hql.toString());
		try {
			Query query = getSession().createQuery(hql.toString());
			Object object = query.uniqueResult();
			if (null == object) {
				return 0;
			}
			return Long.parseLong(object.toString());

		} catch (RuntimeException re) {
			log.error("findEntity for class=" + getEntityClass().getName()
					+ " failed!", re);
			throw re;
		}
	}

	public List findEntityByList(List<Element> elements)
			throws DBErrorException, DBDataErrorException {
		log.debug("findEntity for class:" + getEntityClass().getName());

		StringBuffer hql = new StringBuffer("from "
				+ getEntityClass().getName() + this.createQueryHql(elements));
		try {
			Query query = getSession().createQuery(hql.toString());
			return query.list();
		} catch (RuntimeException re) {
			log.error("findEntity for class=" + getEntityClass().getName()
					+ " failed!", re);
			throw re;
		}
	}

	private String createQueryHql(List<Element> elements) {
		return CreateHqlUtil.createQueryHql(elements);
	}

	public List<E> findEntity(Map<String, ?> equalsMap)
			throws DBErrorException, DBDataErrorException {
		// TODO Auto-generated method stub
		StringBuffer hql = new StringBuffer("from "
				+ getEntityClass().getName()
				+ this.createQueryHql(equalsMap, null, null));
		try {
			Query query = getSession().createQuery(hql.toString());
			return query.list();
		} catch (RuntimeException re) {
			log.error("findEntity for class=" + getEntityClass().getName()
					+ " failed!", re);
			throw new DBErrorException("根据map查询所有相关list");
		} catch (Exception e) {
			log.error("findEntity for class=" + getEntityClass().getName()
					+ " failed!", e);
			throw new DBDataErrorException("根据map查询所有相关list");
		}

	}

	public List findEntityByList(List<Element> elements, int firstResult,
			int maxResult) throws DBErrorException, DBDataErrorException {
		log.debug("findEntity for class:" + getEntityClass().getName());

		StringBuffer hql = new StringBuffer("from "
				+ getEntityClass().getName() + this.createQueryHql(elements));
		try {
			Query query = getSession().createQuery(hql.toString());
			if (maxResult > 0) {
				query.setFirstResult(firstResult).setMaxResults(maxResult);
			}
			return query.list();
		} catch (RuntimeException re) {
			log.error("findEntity for class=" + getEntityClass().getName()
					+ " failed!", re);
			throw re;
		}
	}

}
